﻿// Ass2Srt.cpp: implementation of the CAss2Srt class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Ass2Srt.h"
#include "UnicodeText.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAss2Srt::CAss2Srt() {}

CAss2Srt::~CAss2Srt() {}

bool CAss2Srt::bConvert(LPCTSTR lpAss, LPCTSTR lpSrt)
{
	CUnicodeText ass;
	if (!ass.bReadTextfile(lpAss)) return false;

	CString csLine;
	int iPos=0, iNext, iLen;

	// [Event] 찾아 삼만리
	while (true) {
		iLen = ass.iRead1Line(ass.tcText, ass.lLen, iPos, iNext, csLine);
		if (iLen<0) break;

		iPos = iNext;

		if (csLine.Compare(_T("[Events]"))==0) break;
	}

	if (iLen<0) return FALSE;

	// Format: 찾아 삼만리
	int iOldPos = iPos;	// FFMpeg은 Text와 다음 줄(Dialogue)이 붙는 버그가 있음. 그래서 궁여지책
	while (true) {
		iLen = ass.iRead1Line(ass.tcText, ass.lLen, iPos, iNext, csLine);
		if (iLen<0) break;

		iOldPos = iPos;	// FFMpeg은 Text와 다음 줄(Dialogue)이 붙는 버그가 있음. 그래서 궁여지책
		iPos = iNext;

		if (csLine.Left(7).Compare(_T("Format:"))==0) break;
	}

	if (iLen<0) return false;

	// Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
	// 이것을 분석해야 됨

	csLine.Delete(0, 7);
	csLine.TrimLeft();
	csLine.TrimRight();

	int iStart=-1, iEnd=-1, iText=-1, iTemp, iPosInLine=0;
	CString csTemp;
	while (csLine.GetLength()) {
		iTemp = csLine.Find(_TCHAR(','));
		if (iTemp<0) {
			csTemp = csLine;
			csLine = _T("");
		} else {
			csTemp = csLine.Left(iTemp);
			csLine.Delete(0, iTemp+1);
		}

		csTemp.TrimLeft();
		csTemp.TrimRight();

		if (csTemp.Compare(_T("Start")) == 0)
			iStart = iPosInLine;
		else if (csTemp.Compare(_T("End")) == 0)
			iEnd = iPosInLine;
		// FFMpeg은 Text와 다음 줄(Dialogue)이 붙는 버그가 있음. 그래서 궁여지책
		else if (csTemp.Left(4).Compare(_T("Text")) == 0)
			iText = iPosInLine;

		iPosInLine++;
	}

	csTemp.Format(_T("%d, %d, %d"), iStart, iEnd, iText);

	if (iStart<0 || iEnd<0 || iText<0) return false;

	// Dialogue: 찾아 삼만리
	
	iPos = iOldPos+iText+4;	// FFMpeg은 Text와 다음 줄(Dialogue)이 붙는 버그가 있음. 그래서 궁여지책
	while (ass.tcText[iPos] && _istcntrl(ass.tcText[iPos])) iPos++;
	int iLineNum=1;
	CString csStart, csEnd, csText;

	CUnicodeText srt;
	srt.lLen = ass.lLen * 3;
	srt.tcText = new TCHAR[srt.lLen];
	ZeroMemory(srt.tcText, sizeof(srt.tcText[0])*srt.lLen);

	TCHAR *tc = srt.tcText;
	int iP = 0;

	while (true) {
		iLen = ass.iRead1Line(ass.tcText, ass.lLen, iPos, iNext, csLine);
		if (iLen<0) break;

		iPos = iNext;

		if (csLine.Left(9).Compare(_T("Dialogue:"))) continue;

		csLine.Delete(0, 9);
		csLine.TrimLeft();

		// csLine을 분리하면서 iStart, iEnd, iText만 추출

		iPosInLine=0;
		csStart = csEnd = csText = _T("");
		while (csLine.GetLength()) {
			iTemp = csLine.Find(_TCHAR(','));
			if ((iTemp<0) || (iPosInLine == iText)) {
				csTemp = csLine;
				csLine = _T("");
			} else {
				csTemp = csLine.Left(iTemp);
				csLine.Delete(0, iTemp+1);
			}

			if (iPosInLine == iStart) csStart = csTemp;
			else if (iPosInLine == iEnd) csEnd = csTemp;
			else if (iPosInLine == iText) csText = csTemp;

			iPosInLine++;
		}

		csStart = csRebuildTime(csStart);
		csEnd = csRebuildTime(csEnd);
		csText.TrimLeft();
		csText.TrimRight();

		if (csText.GetLength()) {
			iTemp = _stprintf_s(tc+iP, srt.lLen-iP, _T("%d"), iLineNum++);
			iP += iTemp;
			tc[iP++] = _TCHAR('\r');

			iTemp = _stprintf_s(tc+iP, srt.lLen-iP, _T("%s --> %s"), static_cast<LPCTSTR>(csStart), static_cast<LPCTSTR>(csEnd));
			iP += iTemp;
			tc[iP++] = _TCHAR('\r');

			//iTemp = _stprintf(tc+iP, _T("%s"), csText);
			iTemp = ConvertAndPrints(tc+iP, srt.lLen-iP, csText);
			iP += iTemp;
			tc[iP++] = _TCHAR('\r');
			tc[iP++] = _TCHAR('\r');
		}
	}

	srt.lLen = iP;
	srt.WriteTextfile(lpSrt?lpSrt:lpAss);

	return true;
}

CString CAss2Srt::csRebuildTime(LPCTSTR lpTime)
{
	//0:00:02.53
	//00:00:20,000 --> 00:00:24,400

	CString csOld(lpTime);
	CString h, m, s, ms;

	csOld.TrimLeft();
	csOld.TrimRight();
	csOld.Replace(_TCHAR(' '), NULL);

	int i;

	// hour
	i = csOld.Find(_TCHAR(':'));
	if (i<0) return _T("");

	h = csOld.Left(i);
	h = (_T("00")+h).Right(2);
	csOld.Delete(0, i+1);

	// minute
	i = csOld.Find(_TCHAR(':'));
	if (i<0) return _T("");

	m = csOld.Left(i);
	m = (_T("00")+m).Right(2);
	csOld.Delete(0, i+1);

	// second
	i = csOld.Find(_TCHAR('.'));
	if (i<0) return _T("");

	s = csOld.Left(i);
	s = (_T("00")+s).Right(2);
	csOld.Delete(0, i+1);

	// milisecond
	ms = (csOld+_T("000")).Left(3);

	return (h+_TCHAR(':')+m+_TCHAR(':')+s+_TCHAR(',')+ms);
}

int CAss2Srt::ConvertAndPrints(TCHAR *dst, int len, LPCTSTR lpStr)
{
	// \n, \N : 엔터
	// {\b1} → <b>, 1이 아닌 숫자가 올 수도 있음
	// {\b0} → </b>
	// {\i1} → <i>
	// {\i0} → </i>
	// {\u1} → <u>
	// {\u0} → </u>
	// {\c&Hbbggrr&} → <font color="#rrggbb">, ass는 꼭 6자리가 아닐 수도 있음
	// 기타 {...}는 몽땅 삭제

	CString cs(lpStr);

	cs.Replace(_T("\\n"), _T("\r"));
	cs.Replace(_T("\\N"), _T("\r"));

	while (cs.Replace(_T("\r\r"), _T("\r"))) ;

	cs.TrimRight(_TCHAR('\r'));

	while (true) {
		int i1=cs.Find(_TCHAR('{'));
		int i2=cs.Find(_TCHAR('}'), i1+1);

		if (i1<0) break;
		if (i2<0) {
			cs = cs.Left(i1);
			break;
		}

		CString cs1 = cs.Left(i1);
		CString cs2(cs);
		cs2.Delete(0, i2+1);
		CString csT = cs.Mid(i1+1, i2-i1-1);
		csT.Replace(_TCHAR(' '), NULL);

		if ((csT.GetLength()<2) || (csT.GetAt(0) != _TCHAR('\\'))) csT = _T("");
		else {
			switch (csT.GetAt(1)) {
			case _TCHAR('b'):
				if (csT.Compare(_T("\\b0")) == 0) csT = _T("</b>");
				else csT = _T("<b>");
				break;

			case _TCHAR('i'):
				if (csT.Compare(_T("\\i1")) == 0) csT = _T("<i>");
				else if (csT.Compare(_T("\\i0")) == 0) csT = _T("</i>");
				else csT = _T("");
				break;

			case _TCHAR('u'):
				if (csT.Compare(_T("\\u1")) == 0) csT = _T("<u>");
				else if (csT.Compare(_T("\\u0")) == 0) csT = _T("</u>");
				else csT = _T("");
				break;

			case _TCHAR('c'):
				csT.Delete(0, 2);
				if (csT.IsEmpty()) csT = _T("");
				else if (csT.Left(1).Compare(_T("&")) || csT.Right(1).Compare(_T("&"))) csT = _T("");
				else {
					csT.TrimLeft(_TCHAR('&'));
					csT.TrimRight(_TCHAR('&'));
					csT = (_T("000000")+csT).Right(6);
					//<font color="#rrggbb">
					csT = _T("<font color=\"#") + csT.Right(2) + csT.Mid(2, 2) + csT.Left(2) + _T("\">");
				}
				break;

			default:
				csT = _T("");
			}
		}

		cs = cs1 + csT + cs2;
	}

	while (cs.Replace(_T(" \r"), _T("\r"))) ;
	while (cs.Replace(_T("\r\r"), _T("\r"))) ;
	cs.TrimRight(_TCHAR('\r'));

	if (cs.IsEmpty()) {
		//뺄 거 빼니 아무 것도 없는 경우
		//걍 <b>만 있다고 해주자
		return _stprintf_s(dst, len, _T("<b>"));
	}

	int iRet = cs.GetLength();
	_tcscpy_s(dst, len, static_cast<LPCTSTR>(cs));

	return iRet;
}
